package com.fzu.express.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fzu.express.entity.Order;
import com.fzu.express.entity.Outlet;
import com.fzu.express.entity.WebUser;
import com.fzu.express.enums.BackTagEnum;
import com.fzu.express.enums.OrderStatusEnum;
import com.fzu.express.enums.RoleEnum;
import com.fzu.express.mapper.OrderMapper;
import com.fzu.express.mapper.OutletMapper;
import com.fzu.express.mapper.WebUserMapper;
import com.fzu.express.pojo.Coordinate;
import com.fzu.express.pojo.DashboardSelectVO;
import com.fzu.express.pojo.DashboardVO;
import com.fzu.express.pojo.OrderDetail;
import com.fzu.express.service.OrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzu.express.service.OutletService;
import com.fzu.express.service.WebUserService;
import com.fzu.express.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zyq
 * @since 2022-10-27
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Resource
    private MapUtil mapUtil;
    @Resource
    private OutletService outletService;
    @Resource
    private WebUserService webUserService;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private WebUserMapper webUserMapper;
    @Resource
    private OutletMapper outletMapper;

    @Override
    public PageVO listOrder(Order order, WebUser user, Integer pageNum, Integer pageSize, boolean identityCondition) {
        // 构造分页参数
        Page<Order> pageRequest = new Page<>(pageNum, pageSize);

        // 构造条件查询器
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        // 结合实际场景，可根据订单号，订单状态，发件人手机号，收件人手机号进行订单查询
        // 对条件进行非空判断，不为空时添加查询条件
        // 字符串的非空判断统一使用org.apache.commons.lang3.StringUtils.isNotBlank()
        // 其他类型的非空判断统一使用 != null

        // 订单号
        String orderNo = order.getOrderNo();
        if (StringUtils.isNotBlank(orderNo)) {
            wrapper.eq(Order::getOrderNo, orderNo);
        }

        // 订单状态
        Integer status = order.getStatus();
        if (status != null) {
            wrapper.eq(Order::getStatus, status);
        }

        // 发件人手机号
        String senderPhone = order.getSenderPhone();
        if (StringUtils.isNotBlank(senderPhone)) {
            wrapper.eq(Order::getSenderPhone, senderPhone);
        }

        // 收件人手机号
        String receivedPhone = order.getReceiverPhone();
        if (StringUtils.isNotBlank(receivedPhone)) {
            wrapper.eq(Order::getReceiverPhone, receivedPhone);
        }

        // 揽件网点
        Long startOutlet = order.getStartOutlet();
        if (startOutlet != null) {
            wrapper.eq(Order::getStartOutlet, startOutlet);
        }

        // 派件网点
        Long endOutlet = order.getEndOutlet();
        if (endOutlet != null) {
            wrapper.eq(Order::getEndOutlet, endOutlet);
        }

        // 揽件快递员
        Long startCourier = order.getStartCourier();
        if (startCourier != null) {
            wrapper.eq(Order::getStartCourier, startCourier);
        }

        // 派件快递员
        Long endCourier = order.getEndCourier();
        if (endCourier != null) {
            wrapper.eq(Order::getEndCourier, endCourier);
        }

        if (identityCondition) {
            // 添加用户身份条件
            Integer role = user.getRole();
            Long userId = user.getId();
            if (RoleEnum.USER.getCode().equals(role)) {
                wrapper.eq(Order::getSenderId, userId);
            } else if (RoleEnum.COURIER.getCode().equals(role)) {
                wrapper.and(w -> w.eq(Order::getStartCourier, userId).or().eq(Order::getEndCourier, userId));
                if (order.getStartCourier() != null) {
                    wrapper.or(w -> w.eq(Order::getBackTag, BackTagEnum.BACK.getCode()).eq(Order::getEndCourier, order.getStartCourier()));
                }
                if (order.getEndCourier() != null) {
                    wrapper.or(w -> w.eq(Order::getBackTag, BackTagEnum.BACK.getCode()).eq(Order::getStartCourier, order.getEndCourier()));
                }
            } else if (RoleEnum.OUTLET_MANAGER.getCode().equals(role)) {
                wrapper.and(w -> w.eq(Order::getStartOutlet, user.getOutletId()).or().eq(Order::getEndOutlet, user.getOutletId()));
            }
        }

        // 根据时间倒序
        wrapper.orderByDesc(Order::getCreateTime);
        // 进行查询
        IPage<Order> page = super.page(pageRequest, wrapper);
        return PageVO.convert(page);
    }

    @Override
    public void addOrder(Order order) {
        // 订单号生成
        order.setOrderNo(KeyUtil.generateOrderNo());
        order.setStatus(OrderStatusEnum.WAIT_TAKE.getCode());
        order.setBackTag(BackTagEnum.NORMAL.getCode());

        // 地址拼接
        String address = "";
        if (StringUtils.isNotBlank(order.getSenderProvince())) {
            address += order.getSenderProvince();
        }
        if (StringUtils.isNotBlank(order.getSenderCity())) {
            address += order.getSenderCity();
        }
        if (StringUtils.isNotBlank(order.getSenderTown())) {
            address += order.getSenderTown();
        }
        if (StringUtils.isNotBlank(order.getSenderDetail())) {
            address += order.getSenderDetail();
        }
        if (StringUtils.isBlank(address)) {
            throw new ApiException("寄件地址错误");
        }

        Coordinate coordinate = mapUtil.getCoordinate(address);
        if (coordinate == null) {
            throw new ApiException("寄件地址转换失败，请确认地址信息或稍后重试");
        }

        // 获取距离用户寄件地址最近的快递网点
        Outlet outlet = outletMapper.selectNearestOutlet(coordinate.getLng(), coordinate.getLat(), order.getSenderProvince(), order.getSenderCity());
        if (outlet == null || !outlet.getProvince().equals(order.getSenderProvince()) || !outlet.getCity().equals(order.getSenderCity())) {
            throw new ApiException("抱歉，您所在城市暂未开启服务，敬请期待");
        }

        WebUser webUser = webUserMapper.selectCourier(outlet.getId());
        if (webUser == null) {
            throw new ApiException("抱歉，您所在城市暂无快递员，敬请期待");
        }

        // 分配揽件网点及快递员
        order.setStartOutlet(outlet.getId());
        order.setStartCourier(webUser.getId());

        address = "";
        if (StringUtils.isNotBlank(order.getReceiverProvince())) {
            address += order.getReceiverProvince();
        }
        if (StringUtils.isNotBlank(order.getReceiverCity())) {
            address += order.getReceiverCity();
        }
        if (StringUtils.isNotBlank(order.getReceiverTown())) {
            address += order.getReceiverTown();
        }
        if (StringUtils.isNotBlank(order.getReceiverDetail())) {
            address += order.getReceiverDetail();
        }
        if (StringUtils.isBlank(address)) {
            throw new ApiException("收件地址错误");
        }

        coordinate = mapUtil.getCoordinate(address);
        if (coordinate == null) {
            throw new ApiException("收件地址转换失败，请确认地址信息或稍后重试");
        }

        // 获取距离用户收件地址最近的快递网点
        outlet = outletMapper.selectNearestOutlet(coordinate.getLng(), coordinate.getLat(), order.getReceiverProvince(), order.getReceiverCity());
        if (outlet == null || !outlet.getProvince().equals(order.getReceiverProvince()) || !outlet.getCity().equals(order.getReceiverCity())) {
            throw new ApiException("抱歉，您快件的目标城市暂未开启服务，敬请期待");
        }

        webUser = webUserMapper.selectCourier(outlet.getId());
        if (webUser == null) {
            throw new ApiException("抱歉，您快件的目标城市暂无快递员，敬请期待");
        }

        // 分配收件网点和快递员
        order.setEndOutlet(outlet.getId());
        order.setEndCourier(webUser.getId());
        super.save(order);
    }

    @Override
    public void updateOrder(Order order) {
        // 更新是根据id确定记录的，所以必须对id进行非空判断
        if (order.getId() == null) {
            throw new ApiException("ID值不能为空");
        }
        Integer status = order.getStatus();
        if (OrderStatusEnum.FINISH.getCode().equals(status)) {
            order.setFinishTime(new Date());
        } else if (OrderStatusEnum.CANCELED.getCode().equals(status)) {
            order.setCloseTime(new Date());
        }
        super.updateById(order);
    }

    @Override
    public void deleteOrder(Long id) {
        super.removeById(id);
    }

    @Override
    public OrderDetail getOrderDetail(Long id) {
        Order order = super.getById(id);
        if (order == null) {
            throw new ApiException(ErrorEnum.RECORD_NOT_EXIST);
        }

        Outlet startOutlet = outletService.getById(order.getStartOutlet());
        Outlet endOutlet = outletService.getById(order.getEndOutlet());
        Long startCourier1 = order.getStartCourier();
        WebUser startCourier = webUserService.getById(order.getStartCourier());
        WebUser endCourier = webUserService.getById(order.getEndCourier());

        return new OrderDetail()
                .setData(order)
                .setStartCourier(startCourier)
                .setStartOutlet(startOutlet)
                .setEndCourier(endCourier)
                .setEndOutlet(endOutlet);
    }

    @Override
    public void operate(Order order, WebUser user) {
        Long id = order.getId();
        Integer status = order.getStatus();
        Order selectedOrder = super.getById(id);
        if (selectedOrder == null) {
            throw new ApiException("订单不存在");
        }

        if (OrderStatusEnum.FINISH.getCode().equals(status)) {
            order.setFinishTime(new Date());
        } else if (OrderStatusEnum.CANCELED.getCode().equals(status)) {
            order.setCloseTime(new Date());
        }

        // 更新订单状态
        selectedOrder.setStatus(status);
        super.updateById(selectedOrder);
    }

    @Override
    public DashboardVO dashboard(WebUser user) {
        Long outletId = null;
        Integer role = user.getRole();
        // 网点管理员只能查看自己网点的数据
        if (RoleEnum.OUTLET_MANAGER.getCode().equals(role)) {
            outletId = user.getOutletId();
        }

        // 柱状图数据，最近一周快件数据
        List<String> barLabels = new ArrayList<>(7);
        List<BigDecimal> barCountData = new ArrayList<>(7);
        List<BigDecimal> barWeightData = new ArrayList<>(7);
        List<BigDecimal> barAmountData = new ArrayList<>(7);
        List<DashboardSelectVO> barData = orderMapper.listLatestDateOrder(DateUtil.getAgoDate(6), outletId);
        List<String> dateList = DateUtil.getAgoDateList(6);
        Map<String, DashboardSelectVO> dayDataMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(barData)) {
            dayDataMap = barData.stream().collect(Collectors.toMap(DashboardSelectVO::getLabel, Function.identity()));
        }
        for (String date : dateList) {
            barLabels.add(date);
            DashboardSelectVO vo = dayDataMap.get(date);
            if (vo != null) {
                barCountData.add(vo.getTotal());
                barAmountData.add(vo.getAmount());
                barWeightData.add(vo.getWeight());
            } else {
                barCountData.add(BigDecimal.ZERO);
                barAmountData.add(BigDecimal.ZERO);
                barWeightData.add(BigDecimal.ZERO);
            }
        }

        // 折线图数据，今年各月份快件数趋势图
        int month = DateUtil.getMonth();
        List<String> lineLabels = new ArrayList<>(month);
        List<BigDecimal> lineCountData = new ArrayList<>(month);
        List<DashboardSelectVO> lineData = orderMapper.listMonthOrderCount(outletId);
        Map<String, BigDecimal> monthTotalMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(lineData)) {
            monthTotalMap = lineData.stream().collect(Collectors.toMap(DashboardSelectVO::getLabel, DashboardSelectVO::getTotal));
        }
        for (int i = 1; i <= month; i++) {
            String key = String.valueOf(i);
            BigDecimal total = monthTotalMap.get(key);
            lineLabels.add(key + "月");
            if (total != null) {
                lineCountData.add(total);
            } else {
                lineCountData.add(BigDecimal.ZERO);
            }
        }

        return DashboardVO.builder()
                .lineLabels(lineLabels)
                .lineCountData(lineCountData)
                .barLabels(barLabels)
                .barCountData(barCountData)
                .barAmountData(barAmountData)
                .barWeightData(barWeightData)
                .orderTotal(orderMapper.countAllOrder(outletId))
                .orderNewCount(orderMapper.countTodayOrder(outletId))
                .userTotal(webUserMapper.countAllUser(outletId))
                .userNewCount(webUserMapper.countTodayUser(outletId))
                .build();
    }

    @Override
    public void refuse(Long id, WebUser user) {
        Order order = super.getById(id);
        if (order == null) {
            throw new ApiException(ErrorEnum.RECORD_NOT_EXIST);
        }

        if (!user.getPhone().equals(order.getReceiverPhone()) || BackTagEnum.BACK.getCode().equals(order.getBackTag())) {
            throw new ApiException("非法操作");
        }

        order.setStatus(OrderStatusEnum.TOOK.getCode());
        order.setBackTag(BackTagEnum.BACK.getCode());

        super.updateById(order);
    }

    @Override
    public PageVO listOrderByCourier(Order order, WebUser user, Integer pageNum, Integer pageSize) {
        Integer role = user.getRole();
        if (!RoleEnum.COURIER.getCode().equals(role)) {
            throw new ApiException("非法操作");
        }

        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        // 订单号
        String orderNo = order.getOrderNo();
        if (StringUtils.isNotBlank(orderNo)) {
            wrapper.eq(Order::getOrderNo, orderNo);
        }

        // 订单状态
        Integer status = order.getStatus();
        if (status != null) {
            wrapper.eq(Order::getStatus, status);
        }

        // 发件人手机号
        String senderPhone = order.getSenderPhone();
        if (StringUtils.isNotBlank(senderPhone)) {
            wrapper.eq(Order::getSenderPhone, senderPhone);
        }

        // 收件人手机号
        String receivedPhone = order.getReceiverPhone();
        if (StringUtils.isNotBlank(receivedPhone)) {
            wrapper.eq(Order::getReceiverPhone, receivedPhone);
        }

        Long startCourier = order.getStartCourier();
        Long endCourier = order.getEndCourier();
        if (startCourier != null) {
            wrapper.and(w -> w.
                    eq(Order::getStartCourier, startCourier)
                    .eq(Order::getBackTag, BackTagEnum.NORMAL.getCode())
                    .or()
                    .eq(Order::getEndCourier, startCourier)
                    .eq(Order::getBackTag, BackTagEnum.BACK.getCode()));
        } else {
            wrapper.and(w -> w.
                    eq(Order::getEndCourier, endCourier)
                    .eq(Order::getBackTag, BackTagEnum.NORMAL.getCode())
                    .or()
                    .eq(Order::getStartCourier, endCourier)
                    .eq(Order::getBackTag, BackTagEnum.BACK.getCode()));
        }

        // 根据时间倒序
        wrapper.orderByDesc(Order::getCreateTime);
        // 构造分页参数
        Page<Order> pageRequest = new Page<>(pageNum, pageSize);
        // 进行查询
        IPage<Order> page = super.page(pageRequest, wrapper);
        return PageVO.convert(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long batchOperate(Integer status, WebUser user) {
        Integer role = user.getRole();
        Long outletId = user.getOutletId();
        Long userId = user.getId();
        if (RoleEnum.USER.getCode().equals(role) || RoleEnum.SYSTEM_MANAGER.getCode().equals(role)) {
            throw new ApiException("非法操作");
        }

        Long res = 0L;
        // 快递员 已到达3->派送中4
        if (RoleEnum.COURIER.getCode().equals(role)) {
            if (!OrderStatusEnum.OUT_OF_DELIVERY.getCode().equals(status)) {
                throw new ApiException("非法操作");
            }
            res = orderMapper.updateBatchByCourier(userId, status);
        }

        // 网点管理员 已揽件1->运输中2、运输中2->已到达3
        if (RoleEnum.OUTLET_MANAGER.getCode().equals(role)) {
            if (!OrderStatusEnum.ARRIVED.getCode().equals(status) && !OrderStatusEnum.TRANSPORT.getCode().equals(status)) {
                throw new ApiException("非法操作");
            }
            res = orderMapper.updateBatchByOutletManager(outletId, status);
        }
        return res;
    }
}
